package ru.spbu.math.seabattle.client.jms;

import java.io.Serializable;
import java.util.concurrent.atomic.AtomicLong;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;

import ru.spbu.math.seabattle.client.IClient;
import ru.spbu.math.seabattle.client.jms.common.JmsQueueHelper;
import ru.spbu.math.seabattle.client.jms.gui.LoginFormGUI;
import ru.spbu.math.seabattle.client.messages.*;

import ru.spbu.math.seabattle.entity.Action;
import ru.spbu.math.seabattle.entity.FieldModel;
import ru.spbu.math.seabattle.entity.PlayerID;

import ru.spbu.math.seabattle.server.IServer;
import ru.spbu.math.seabattle.server.messages.*;


public class SeaBattleClientWrapper {

	public static void main(String[] args) {
		new SeaBattleClientWrapper();
	}
	
	public static final String QUEUE_NAME = "super-mega-queue";
	
	private static final AtomicLong queueId = new AtomicLong();
	
	private String serverAddress;
	
	private SeaBattleClient wrappedClient = new SeaBattleClient();

	private JmsQueueHelper serverQueue;
	private JmsQueueHelper clientQueue;
	
	private LoginFormGUI loginForm;
	
	public SeaBattleClientWrapper() {
		
		loginForm = new LoginFormGUI(this);
		loginForm.setVisible(true);
	}
	
	public void connect(String url, String name) throws JMSException {
		
		if (!url.startsWith("tcp://")) {
			serverAddress = "tcp://" + url;
		} else {
			serverAddress = url;
		}
		
		serverQueue = new JmsQueueHelper();
		serverQueue.start(serverAddress, QUEUE_NAME);
		
		clientQueue = new JmsQueueHelper();
		clientQueue.start(serverAddress, "client-queue-" + queueId.incrementAndGet());
		System.out.println(name + ": queue name - " + "client-queue " + (int)(Math.random() * 1000000000));
		clientQueue.addMessageListener(new MessageListener() {
			
			@Override
			public void onMessage(Message message) {
				try {
					Serializable object = ((ObjectMessage) message).getObject();
					
					if (object instanceof OnEnemyTurnEndedMessage) {
						OnEnemyTurnEndedMessage mes = (OnEnemyTurnEndedMessage) object;
						wrappedClient.onEnemyTurnEnded(mes.getTurnResult());
					} else if (object instanceof OnEnemyTurnStartedMessage) {
						//OnEnemyTurnStartedMessage mes = (OnEnemyTurnStartedMessage) object;
						wrappedClient.onEnemyTurnStarted();
					} else if (object instanceof OnGameEndedMessage) {
						OnGameEndedMessage mes = (OnGameEndedMessage) object;
						wrappedClient.onGameEnded(mes.getGameResult());
					} else if (object instanceof OnGameRequestMessage) {
						OnGameRequestMessage mes = (OnGameRequestMessage) object;
						wrappedClient.onGameRequest(mes.getOpponentId(), mes.getName());
					} else if (object instanceof OnGameRequestRefusedMessage) {
						OnGameRequestRefusedMessage mes = (OnGameRequestRefusedMessage) object;
						wrappedClient.onGameRequestRefused(mes.getOpponentId());
					} else if (object instanceof OnGameRequestWithdrawnMessage) {
						OnGameRequestWithdrawnMessage mes = (OnGameRequestWithdrawnMessage) object;
						wrappedClient.onGameRequestWithdrawn(mes.getOpponentId());
					} else if (object instanceof OnGameStartedMessage) {
						//OnGameStartedMessage mes = (OnGameStartedMessage) object;
						wrappedClient.onGameStarted();
					} else if (object instanceof OnPlayerJoinedMessage) {
						OnPlayerJoinedMessage mes = (OnPlayerJoinedMessage) object;
						wrappedClient.onPlayerJoined(mes.getPlayerId(), mes.getPlayerName());
					} else if (object instanceof OnPlayerLeftMessage) {
						OnPlayerLeftMessage mes = (OnPlayerLeftMessage) object;
						wrappedClient.onPlayerLeft(mes.getPlayerId());
					} else if (object instanceof OnYourTurnEndedMessage) {
						OnYourTurnEndedMessage mes = (OnYourTurnEndedMessage) object;
						wrappedClient.onYourTurnEnded(mes.getTurnResult());
					} else if (object instanceof OnYourTurnStartedMessage) {
						//OnYourTurnStartedMessage mes = (OnYourTurnStartedMessage) object;
						wrappedClient.onYourTurnStarted();
					} else if (object instanceof WelcomeMessage) {
						System.out.println("CLIENT WRAPPER: Welcome message arrived.");
						loginForm.setVisible(false);
						loginForm = null;
						WelcomeMessage mes = (WelcomeMessage) object;
						wrappedClient.welcome(mes.getGivenId(), mes.getGivenName());
					} else if (object instanceof OnPlayerAddedMessage) {
						OnPlayerAddedMessage mes = (OnPlayerAddedMessage) object;
						wrappedClient.onPlayerAddedOrRemoved(mes.isAdded(), mes.getId(), mes.getName());
					} else {
						System.out.println("CLIENT: Unknown message arrived");
					}
				} catch(JMSException e) {
					e.printStackTrace();
				}
			}
		});
		
		wrappedClient.init(new JMSServer(), name);
	}
	
	private class JMSServer implements IServer {

		@Override
		public void acceptGameRequest(PlayerID myID, PlayerID opponentID) {
			try {
				serverQueue.sendFrom(new AcceptGameRequestMessage(myID, opponentID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void goodbye(PlayerID myID) {
			try {
				serverQueue.sendFrom(new GoodbyeMessage(myID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void hello(IClient client, String myName) {
			try {
				serverQueue.sendFrom(new HelloMessage(myName), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void makeTurn(PlayerID myID, Action action) {
			try {
				serverQueue.sendFrom(new MakeTurnMessage(action, myID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void refuseGameRequest(PlayerID myID, PlayerID opponentID) {
			try {
				serverQueue.sendFrom(new RefuseGameRequestMessage(myID, opponentID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void requestGame(PlayerID myID) {
			try {
				serverQueue.sendFrom(new RequestGameMessage(myID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void requestGame(PlayerID myID, PlayerID opponentID) {
			try {
				serverQueue.sendFrom(new RequestOpponentMessage(myID, opponentID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void setField(PlayerID myID, FieldModel field) {
			try {
				serverQueue.sendFrom(new SetFieldMessage(field, myID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void withdrawGame(PlayerID myID) {
			try {
				serverQueue.sendFrom(new WithdrawGameMessage(myID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}

		@Override
		public void withdrawGame(PlayerID myID, PlayerID opponentID) {
			try {
				serverQueue.sendFrom(new WithdrawOpponentMessage(myID, opponentID), clientQueue.getDestination());
			} catch (JMSException e) {
				e.printStackTrace();
			}		
		}
		
	}
	

}
